package com.wolfpire.workflow.spring.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.util.Iterator;
import java.util.List;

import javax.annotation.Resource;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.jbpm.api.ProcessDefinition;
import org.jbpm.api.RepositoryService;
import org.springframework.stereotype.Service;

import com.wolfpire.system.common.base.dao.IBaseHibernateDao;
import com.wolfpire.system.common.base.service.impl.BaseHibernateService;
import com.wolfpire.workflow.dao.NodeActorDao;
import com.wolfpire.workflow.dao.NodeDao;
import com.wolfpire.workflow.dao.OperateDao;
import com.wolfpire.workflow.dao.WorkflowDao;
import com.wolfpire.workflow.em.NodeType;
import com.wolfpire.workflow.om.Node;
import com.wolfpire.workflow.om.NodeActor;
import com.wolfpire.workflow.om.NodeOperate;
import com.wolfpire.workflow.om.Workflow;
import com.wolfpire.workflow.spring.DeployWorkFlowService;
import com.wolfpire.workflow.utils.JbpmUtil;

/**
 * 部署工作流
 * @author liushx
 *
 */
@Service("deployWorkflowService")
public class DeployWorkFlowServiceImpl extends BaseHibernateService<Workflow, Long> implements DeployWorkFlowService {
	
	/** 流程表单 */
	private static final String FORM_TYPE = "forms";
	/** 参与者类型  */
//	private static final String ACTOR_TYPE = "catalog";
	private static final String ACTOR_TYPE = "actorType";	
	/** 参与者ID-名称 */
//	private static final String ACTOR_VALUE = "candidateIds";
	private static final String ACTOR_VALUE = "actorIds";
	/** 流程操作 */
	private static final String OPERATE = "operate";
	/** 回收/撤销 */
	private static final String RECOVER = "recover";
	/** 流程限时配置 */
	private static final String TIME_LIMIT = "timeLimit";
	/** 动态选人 */
	private static final String DYNAMIC_SELECT = "dynamicSelect";
	/** 动态跳转 */
	private static final String DYNAMIC_JUMP = "dynamicJump";
	/** 转办  */
	private static final String TRUN_TODO = "trunTodo";
	/** 文书附件  */
	private static final String FLOW_ATTR = "flowAttr";
	/** 决策表达式 */
	private static final String EXPR_TEXT = "exprText";
	
	@Resource private WorkflowDao workflowDao;
	
	@Resource private NodeDao nodeDao;
	
	@Resource private NodeActorDao nodeActorDao;
	
	@Resource private OperateDao operateDao;
	
	@Override
	public List<Workflow> list(Workflow entity) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	protected IBaseHibernateDao<Workflow, Long> getEntityDao() {
		return this.workflowDao;
	}

	@SuppressWarnings("unchecked")
	@Override
	public String deployWorkFlow(RepositoryService repositoryService,
			Workflow workflow, String xmlFilePath) throws Exception {
		/* 转化图形化XML文件，生成JBPM适配的XML文件 */
		String covertFileName = filterXmlFile(workflow.getFilePath(), xmlFilePath);
		String deployWorkFlowId = JbpmUtil.deployProcessDefinition(repositoryService, xmlFilePath + covertFileName);
		/* 获取部署的流程定义  */	
		ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().deploymentId(deployWorkFlowId).uniqueResult();			
		
		/* 扩展自定义数据持久化 处理XML配置文件中一些需要持久化的，但又不属于JBPM流程配置的拓展配置数据 */
		//解析图形化生成的XML文件 
		File file = new File(xmlFilePath + workflow.getFilePath());
		Element root = new SAXReader().read(file).getRootElement();//获取根节点
		
		String formTypeId = root.attributeValue(FORM_TYPE);
		Long deploymentId = Long.valueOf(pd.getDeploymentId());
		//流程时限
		String timeLimit = root.attributeValue(TIME_LIMIT);
		
		
		addNode(root.elementIterator(), deploymentId, workflow.getWorkFlowId());
		
		//String formTypeId = persistentCustomData(pd, workflow, xmlFilePath);			
		workflow.setDeploymentId(Long.valueOf(deployWorkFlowId));
		workflow.setFormTypeId(formTypeId);
		if(timeLimit != null)
		workflow.setTimeLimit(Long.valueOf(timeLimit));
		workflow.setVersion(Long.valueOf(pd.getVersion()));
		workflowDao.saveOrUpdate(workflow);
		
		return deployWorkFlowId;
	}
	
	/**
	 * 过滤XML自定义配置文件，清除各配置节点对于流程无用的图形化配置属性
	 * @param xmlFileName xml文件名称
	 * @param xmlFilePath xml文件路径
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	private String filterXmlFile(String xmlFileName, String xmlFilePath) throws Exception {

		String retFileName = xmlFileName.substring(0, xmlFileName.indexOf(".")) + "_deploy.jpdl.xml";
		
		/* DOM4J解析图形化生成的XML文件 */
		File file = new File(xmlFilePath + xmlFileName);
		SAXReader reader = new SAXReader();
		Document doc = reader.read(file);
		Element root = doc.getRootElement();//获取根节点
		removeAttribute(root, new String[]{FORM_TYPE});
		
		/* 解析任务节点 */
		Iterator<Element> taskIterator = root.elementIterator(NodeType.TASK.getName());	 			
		while(taskIterator.hasNext()) {
			
			Element taskElement = (Element)taskIterator.next(); 
			removeAttribute(taskElement, new String[]{ACTOR_TYPE, ACTOR_VALUE, OPERATE, FORM_TYPE});
		}
		
		/* 解析Transition */
		Iterator<Element> decisionIterator = root.elementIterator(NodeType.DECISION.getName());	 
		while(decisionIterator.hasNext()) {				
			Element decisionElement = (Element)decisionIterator.next();
			removeAttribute(decisionElement, new String[]{"assignType"});

		}		
		
		/* 输出修改后的XML文件 */
		OutputFormat format = OutputFormat.createPrettyPrint();     
     	format.setEncoding("UTF-8");  // 设置XML文件的编码格式 UTF-8  
     	XMLWriter writer = new XMLWriter(new FileOutputStream(new File(xmlFilePath + "/" + retFileName)), format);  
     	writer.write(doc);
     	writer.close();

		return retFileName;
	}

	private void addNode(Iterator<Element> elItor, Long deploymentId, Long workFlowId){
		while(elItor.hasNext()) {
			Element el = (Element)elItor.next();
			Node node = new Node();
			node.setDeploymentId(deploymentId);
			node.setWorkFlowId(workFlowId);
			node.setNodeType(NodeType.START.getIndex());
			node.setNodeName(el.attributeValue("name"));
			
			String forms = el.attributeValue("forms");

			String recover = el.attributeValue(RECOVER);//是否可以撤销
			String timeLimit = el.attributeValue(TIME_LIMIT);//审核超时配置
			String dynamicSelect = el.attributeValue(DYNAMIC_SELECT);//审核超时配置
			String dynamicJump = el.attributeValue(DYNAMIC_JUMP);//审核超时配置
			String trunTodo = el.attributeValue(TRUN_TODO);
			String flowAttr = el.attributeValue(FLOW_ATTR);
			if(forms != null && !"".equals(forms))
				node.setFormTypeId(Long.valueOf(forms));
			if(recover != null)
				node.setIsRevoke(Integer.valueOf(recover));
			if(timeLimit != null)
				node.setTimeLimit(Long.valueOf(timeLimit));
			
			if(dynamicSelect != null)
				node.setDynamicSelect(dynamicSelect);
			if(dynamicJump != null)
				node.setDynamicJump(dynamicJump);
			if(trunTodo != null)
				node.setTrunTodo(trunTodo);
			if(flowAttr != null)
				node.setFileUp(flowAttr);
		
			if(NodeType.START.getName().equals(el.getName())){
				//添加流程开始节点
				node.setNodeName(el.attributeValue("name"));
			} else if(NodeType.END.getName().equals(el.getName())){
				//添加流程结束节点
				node.setNodeType(NodeType.END.getIndex());
			} else if (NodeType.FORK.getName().equals(el.getName())) {
				node.setNodeType(NodeType.FORK.getIndex());
				
			} else if (NodeType.JOIN.getName().equals(el.getName())) {	
				node.setNodeType(NodeType.JOIN.getIndex());
			} else if (NodeType.DECISION.getName().equals(el.getName())) {
				//决策节点
				node.setNodeType(NodeType.DECISION.getIndex());
				String exprText = el.attributeValue(EXPR_TEXT);//决策表达式
				if(exprText != null) node.setExprText(exprText);
			} else if (NodeType.SUB_PROCESS.getName().equals(el.getName())) {
				//添加子流程
				node.setNodeType(NodeType.SUB_PROCESS.getIndex());
			} else if(NodeType.TASK.getName().equals(el.getName())) {
				node.setNodeType(NodeType.TASK.getIndex());
				//进行转换设置，把角色和人员都转成人进行处理
				Element assignmentEle = el.element("assignment-handler");
				if(assignmentEle != null) {
					node.setHandleClass(assignmentEle.attributeValue("expr"));
				}
				
				//判断是否会签
				String sign = el.attributeValue("sign");
				String signValue = el.attributeValue("signValue");
				if(sign != null){
					node.setNodeType(NodeType.SIGN.getIndex());
					node.setStrategy(Integer.parseInt(sign));
					if(signValue != null)
					node.setStrategyValue(Integer.parseInt(signValue));
				}
				this.nodeDao.save(node);
				//节点参与者
				String actorType = el.attributeValue(ACTOR_TYPE);
				String candidateIds = el.attributeValue(ACTOR_VALUE);	
				if (candidateIds != null && candidateIds.trim().length() > 0) {
					String[] idArray = candidateIds.split(",");	
					for(String actorId : idArray) {
						String[] actors = actorId.split("-");
						NodeActor property = new NodeActor(); 
						property.setNodeId(node.getNodeId());
						property.setActorId(Long.valueOf(actors[0]));
						property.setActorName(actors[1]);
						property.setActorType(actorType);
						nodeActorDao.save(property);
					}
				}
				//节点操作
				String operateStr = el.attributeValue(OPERATE);
				if (operateStr != null && operateStr.trim().length() > 0) {
					String[] operateArray = operateStr.split(",");	
					for(String oper : operateArray) {
						String[] operate = oper.split("-");
						NodeOperate nodeOperate = new NodeOperate(); 
						nodeOperate.setNodeId(node.getNodeId());
						nodeOperate.setOperateId(Long.valueOf(operate[0]));
						nodeOperate.setAnotherName(operate[1]);
						operateDao.saveNodeOperate(nodeOperate);
					}
				}
			}
			
			nodeDao.save(node);
		}
	}

	/**
	 * 移除节点属性
	 * @param el
	 * @param attrNames
	 */
	private void removeAttribute(Element el, String[] attrNames){
		if(attrNames.length > 0){
			for (int i = 0; i < attrNames.length; i++) {
				Attribute attr = el.attribute(attrNames[i]);
				if(attr != null) {
					el.remove(attr);
				}
			}
		}
	}

}
